//
//  Keychain.m
//  MailDelivery
//
//  Created by Dante Palacios on 9/24/09.
//  Copyright 2009 Dante Palacios. All rights reserved.
//

#import "Keychain.h"
#import "KeychainItem.h"

#import "NSDictionaryAdditions.h"

#import "Funtions.h"
#import "Macros.h"


@implementation Keychain

static Keychain *sharedKeychain = nil;

+ (Keychain *)sharedKeychain
{
	@synchronized(self)
	{
		if (!sharedKeychain) 
		{
			sharedKeychain = [[self alloc] init];
		}
	}
	
	return sharedKeychain;
}

- (id)init
{
    self = [super init];
	if (self)
	{
		OSStatus status = SecKeychainCopyDefault(&_keychain);
		
		if (status != CSSM_OK)
		{
			[self release], self = nil;
			return nil;
		}
	}
	
	return self;
}

- (void)dealloc
{
    if (sharedKeychain == self) return;
    
	if (_keychain) 
	{
		CFRelease(_keychain);
	}
	
	[super dealloc];
}

- (KeychainItem *)addKeychainItemForAccount:(NSDictionary *)account
{
	//NSLog(@"%@ addKeychainItemForAccount \"%@\"", self, account.name);
	NSString *hostName = [account hostName];
	NSString *userName = [account userName];
	
	if (!hostName || ![hostName length] || !userName || ![userName length])
	{
		return nil;
	}
	
	KeychainItem *item = [self keychainItemForAccount:account];
	if (item) 
	{
		//NSLog(@"%@: KeychainItem exist…", self);
		return item;
	}
	
	NSString *password = [account password];
	if (!password.length)
	{
		//NSLog(@"%@: Password can not be an empty string…", self);
		return nil;
	}
	
	NSInteger port = [account port];
	
	const char *pass = [password UTF8String];
	const char *server = [hostName UTF8String];
	const char *user = [userName UTF8String];
	const char *path = "";
	
	SecKeychainItemRef itemRef;
	
	OSStatus status = SecKeychainAddInternetPassword(_keychain, 
													 (UInt32)strlen(server), 
													 server, 
													 0, 
													 NULL, 
													 (UInt32)strlen(user), 
													 user, 
													 (UInt32)strlen(path), 
													 path, 
													 port, 
													 kSecProtocolTypeSMTP, 
													 kSecAuthenticationTypeDefault, 
													(UInt32)strlen(pass), 
													 (void *)pass, 
													 &itemRef);
	
	if (status != noErr)
	{
		CFStringRef errMess = SecCopyErrorMessageString(status, NULL);
		MailDeliveryLog(@"%@", (NSString *)errMess);
		CFRelease(errMess);
		return nil;
	}
	
	item = [[KeychainItem alloc] init];
	item.keychainItemRef = itemRef;
	item.hostName = hostName;
	item.userName = userName;
	item.password = password;
	
	return [item autorelease];
}

- (KeychainItem *)keychainItemForAccount:(NSDictionary *)account
{
	//NSLog(@"%@ keychainItemForAccount:%@", self, account);
	
	NSString *hostName = [account hostName];
	NSString *userName = [account userName];
	if (!hostName || !userName) return nil;
	
	const char *serviceName = [hostName UTF8String];
	const char *serviceUserName = [userName UTF8String];
	const char *path = "";
	
	UInt32 passwordLength = 0;
	char *pass = nil;
	
	OSStatus status = noErr;
	SecKeychainItemRef itemRef;
	
	if (IsMobileMeHost(hostName))
	{
		serviceName = "iTools";
		
		status = SecKeychainFindGenericPassword(_keychain, 
												(UInt32)strlen(serviceName), 
												serviceName, 
												(UInt32)strlen(serviceUserName), 
												serviceUserName, 
												&passwordLength, 
												(void **)&pass, 
												&itemRef);
	}
	else {
		status = SecKeychainFindInternetPassword(_keychain, 
												(UInt32)strlen(serviceName), 
												 serviceName, 
												 0, 
												 NULL, 
												 (UInt32)strlen(serviceUserName), 
												 serviceUserName, 
												 (UInt32)strlen(path), 
												 path, 
												 0, 
												 kSecAuthenticationTypeAny, 
												 kSecAuthenticationTypeAny, 
												 &passwordLength, 
												 (void **)&pass, 
												 &itemRef);
	}
	
	if (status != noErr)
	{
		CFStringRef errMess = SecCopyErrorMessageString(status, NULL);
		MailDeliveryLog(@"%@:%@", [self class], (NSString *)errMess);
		CFRelease(errMess);
		return nil;
	}
	
	NSString *password = [[[NSString alloc] initWithBytes:pass length:passwordLength encoding:NSUTF8StringEncoding] autorelease];
	
	KeychainItem *item = [[KeychainItem alloc] init];
	item.keychainItemRef = itemRef;
	item.hostName = hostName;
	item.userName = userName;
	item.password = password;
	
	return [item autorelease];
}

@end